#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QCheckBox>
#include <QScrollBar>
#include <QScrollArea>
#include <QVBoxLayout>
#include <QSizePolicy>
#include <QGroupBox>
#include "fx_chorus.h"
#include "fx_compressor.h"
#include "fx_distortion.h"
#include "fx_echo.h"
#include "fx_flanger.h"
#include "fx_gargle.h"
#include "fx_parameq.h"
#include "fx_reverse.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    if(!BASS_Init(-1,44100,0,0,0)) {
        msgBox.setText("Ошибка!");
        msgBox.exec();
        return;
    }

    magic = new Magic();
    connect(magic, SIGNAL(devices(QStringList)), this, SLOT(getDevices(QStringList)));
    connect(magic, SIGNAL(newRecord(QString)), this, SLOT(addTrack(QString)));
    magic->getDevices();
    isRecord = false;
    exporter = new Exporter();
    connect(exporter, SIGNAL(channels()), this, SLOT(channels()));
    connect(this, SIGNAL(sendChannels(QVector<HSTREAM>)), exporter, SLOT(getChannels(QVector<HSTREAM>)));

        maxTime = 0;
        isPlaying = false;
        // Кнопки будут размещены Grid layout
        gLayoutChoiceRegion = new QGridLayout();
        // Располагаться будут на виджете
        widgetChoiceRegion = new QWidget();
        widgetChoiceRegion->setLayout(gLayoutChoiceRegion);
        // Помещаем виджет с кнопками в скролл зону
       scrollArea = new QScrollArea();
        scrollArea->setFrameShape(QFrame::NoFrame);
    //    scrollArea->setWidgetResizable(true);
        scrollArea->setWidget(widgetChoiceRegion);
        // Для размещения скролл-зоны с кнопками на group box
        // нужно будет создать еще один компоновщик - компоновщик group box
        // поместим на нем скролл-зону
        vBoxLayout = new QVBoxLayout();
        vBoxLayout->addWidget(scrollArea);

        groupBoxChoiceRegion = new QGroupBox();
        groupBoxChoiceRegion->setTitle("");
        groupBoxChoiceRegion->setLayout(vBoxLayout);
        ui->verticalLayout->addWidget(groupBoxChoiceRegion);

        //
        QPixmap pixmap(QCoreApplication::applicationDirPath() + "/icon/delete.png");
        QIcon ButtonIcon(pixmap);
        ui->pushButton_12->setIcon(ButtonIcon);

        QPixmap eff(QCoreApplication::applicationDirPath() + "/icon/effect_del.png");
        QIcon ButtonIconEff(eff);
        ui->pushButton_16->setIcon(ButtonIconEff);
        ui->pushButton_16->setIconSize(QSize(32,32));

        QPixmap play(QCoreApplication::applicationDirPath() + "/icon/play.png");
        QIcon play_b(play);
        ui->pushButton->setIcon(play_b);
        ui->pushButton->setIconSize(QSize(32,32));

        QPixmap pause(QCoreApplication::applicationDirPath() + "/icon/pause.png");
        QIcon ButtonIconp(pause);
        ui->pushButton_2->setIcon(ButtonIconp);
        ui->pushButton_2->setIconSize(QSize(32,32));

        QPixmap stop(QCoreApplication::applicationDirPath() + "/icon/stop.png");
        QIcon ButtonIcons(stop);
        ui->pushButton_3->setIcon(ButtonIcons);
        ui->pushButton_3->setIconSize(QSize(32,32));

        QPixmap lab(QCoreApplication::applicationDirPath() + "/icon/volume.png");
        ui->label_3->setText("");
        ui->label_3->setPixmap(lab);

        QPixmap lab1(QCoreApplication::applicationDirPath() + "/icon/undo.png");
        ui->label_4->setText("");
        ui->label_4->setPixmap(lab1);
        ui->label_4->installEventFilter(this);

        QPixmap lab2(QCoreApplication::applicationDirPath() + "/icon/undo.png");
        ui->label_5->setText("");
        ui->label_5->setPixmap(lab2);
        ui->label_5->installEventFilter(this);

        QPixmap lab3(QCoreApplication::applicationDirPath() + "/icon/undo.png");
        ui->label_6->setText("");
        ui->label_6->setPixmap(lab3);
        ui->label_6->installEventFilter(this);

        QPixmap record(QCoreApplication::applicationDirPath() + "/icon/record_play.png");
        QIcon ButtonIconRecord(record);
        ui->pushButton_rec->setIcon(ButtonIconRecord);
        ui->pushButton_rec->setIconSize(QSize(32,32));


}

MainWindow::~MainWindow()
{
    BASS_Free();
    delete ui;
}

bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{

    if(event->type() == QEvent::MouseButtonPress)
    {

        if (obj == ui->label_4)
            ui->horizontalSlider_temp->setValue(0);
        else if (obj == ui->label_5)
            ui->horizontalSlider_pitch->setValue(0);
        else if (obj == ui->label_6)
            ui->horizontalSlider_freq->setValue(44100);
        else
            return QObject::eventFilter(obj, event);
        for (int i = 0; i < check_box.size(); i++)
            if (check_box[i]->isChecked())
            {
                if (obj== ui->label_4)
                    list[i]->addAttribute(BASS_ATTRIB_TEMPO, 0);
                else if (obj== ui->label_5)
                    list[i]->addAttribute(BASS_ATTRIB_TEMPO_PITCH, 0);
                else if (obj== ui->label_6){
                    list[i]->addAttribute(BASS_ATTRIB_FREQ, 44100);
                }
            }

        return true;
    }
    else
         return QObject::eventFilter(obj, event);
}

void MainWindow::dropEvent( QDropEvent *event )
{
    const QMimeData* p_mimeData = event->mimeData();
    if ( p_mimeData->hasUrls() )
    {
        QList<QUrl> urlList = p_mimeData->urls();
        for ( int i = 0; i < urlList.size(); ++i )
        {
            qDebug()<< urlList.at(i).toString() ;
            addTrack(urlList.at(i).toString().remove("file:///"));
        }
    }
    event->acceptProposedAction();
}

void MainWindow::dragEnterEvent( QDragEnterEvent* event )
{
    event->acceptProposedAction();
}

void MainWindow::dragMoveEvent( QDragMoveEvent* event )
{
    event->acceptProposedAction();
}

void MainWindow::dragLeaveEvent( QDragLeaveEvent* event )
{
    event->accept();
}

void MainWindow::play()
{
    isPlaying = true;
    actTrig(ui->horizontalSlider->value());
}

void MainWindow::pause()
{
    int count = list.size();
    for(int i = 0; i< count; i++)
        if (count != list.size())
            return;
        else
            list[i]->pause();
    isPlaying = false;
}

void MainWindow::stop()
{
     int count = list.size();
    for(int i = 0; i< count; i++)
        if (count != list.size())
            return;
        else
            list[i]->stop();
    isPlaying = false;
    ui->timeLabel->setText("00:00 / 00:00");
}

void MainWindow::valueChanged(int arg)
{

}


//при перетаскивании ползунка
void MainWindow::actTrig(int arg)
{
    int count = list.size();
    for(int i = 0; i< count; i++)
    {
        if (count != list.size())
            return;
        list[i]->changePosition(arg);
        if (!list[i]->playing && isPlaying)
            list[i]->resume();
    }
    if (list.size() == 0)
        maxTime = 0;
    setTime(ui->horizontalSlider->value(), maxTime);
}


//слот для муз потока
void MainWindow::moveSlider(double arg1, double arg2)
{
    if (maxTime < arg2)
        maxTime = arg2;
    if (maxTime == arg2)
    {
        ui->horizontalSlider->setValue(arg1);
        ui->horizontalSlider->setMaximum(arg2);
        ui->horizontalSlider->setPageStep(arg2 / 10);

        setTime(arg1, arg2);
    }
}

void MainWindow::addTrack(QString fileName)
{
    if (fileName != "")
    {
        AudioThread* pt = new AudioThread(this);
        if(!pt->play(fileName))
        {
            QMessageBox msgBox;
            msgBox.setText("Can't not add file");
             msgBox.exec();
            return;
        }
                qDebug()<<"end";
        connect(pt, SIGNAL(delTrack(AudioThread*)), this, SLOT(del(AudioThread*)));
        pt->stop();
        list.push_back(pt);
        connect(pt, SIGNAL(curPos(double,double)), this, SLOT(moveSlider(double,double)));
        ui->verticalLayout->removeWidget(groupBoxChoiceRegion);

        // add waveform
        WaveForm *wf = new WaveForm(fileName);
        wf->setFixedSize(800, 200);
        connect(pt, SIGNAL(curPos(double,double)), wf, SLOT(moveSlider(double, double)));
        waves.push_back(wf);

        editor_widget* edit = new editor_widget();
        edit->setFixedSize(122, 200);
        edit->setConnect(pt, wf);
        check_box.push_back(edit->getCheck());
        list_leftRight.push_back(edit->getChannel());
        list_volume.push_back(edit->getVolume());

        gLayoutChoiceRegion->addWidget(edit,gLayoutChoiceRegion->rowCount(), 0, Qt::AlignCenter);
        gLayoutChoiceRegion->addWidget(wf, gLayoutChoiceRegion->rowCount() - 1, 1, Qt::AlignCenter);


        widgetChoiceRegion = new QWidget();
        widgetChoiceRegion->setLayout(gLayoutChoiceRegion);
        scrollArea->setFrameShape(QFrame::NoFrame);
        scrollArea->setWidget(widgetChoiceRegion);
        groupBoxChoiceRegion->setLayout(vBoxLayout);
        calcMaxTime();
    }
}



//добавить дорожку
void MainWindow::addTrack()
{
    stop();
    QString fileName = QFileDialog::getOpenFileName(this, tr("Open Audio File"), "C:\\", tr("Audio Files (*.mp3 *.wav)"));
    addTrack(fileName);
}

//удалить дорожку
void MainWindow::del(AudioThread* track)
{
    int index = -1;
    for (int i = 0; i < list.size(); i++)
        if (list[i] == track){
            index = i;
            break;
        }
    qDebug()<<"index "<<QString::number(index);
    if (index == -1)
        qDebug()<<"error del track";
    else {
        qDebug()<<"!";
        editor_widget* edit = (editor_widget*)gLayoutChoiceRegion->takeAt(index * 2)->widget();
        edit->disconnectWidgets();
        gLayoutChoiceRegion->takeAt(index * 2);
        delete edit;

        check_box.remove(index);
        list_volume.remove(index);
        list_leftRight.remove(index);

        WaveForm* w = waves[index];


        w->disconnect();

        waves.remove(index);
        if (w != NULL)    delete w;

        AudioThread* p = list[index];
        list[index]->disconnect();
        list[index]->stop();
        list.remove(index);
        if (p != NULL) delete p;

        widgetChoiceRegion = new QWidget();
        widgetChoiceRegion->setLayout(gLayoutChoiceRegion);
        scrollArea->setFrameShape(QFrame::NoFrame);
        scrollArea->setWidget(widgetChoiceRegion);
        groupBoxChoiceRegion->setLayout(vBoxLayout);

       // if (list.size() == 0)
        //    ui->horizontalSlider->setValue(0);
        calcMaxTime();
        qDebug()<<"!";
    }
}

void MainWindow::exportTrack()
{
    stop();

    QString fileName = QFileDialog::getSaveFileName(this, tr("Save Audio File"), "sound.wav", tr("Audio Files (*.wav)"));
    exporter->write(fileName);
}

void MainWindow::form_fx(QAction * act)
{
    qDebug()<<act->text();
    fx_basic* form;
    QString str(act->text());
    if (str == "Import") {
        addTrack();
        return;
    }
    else if (str == "Export") {
        exportTrack();
        return;
    }
    else if (str == "Exit"){
        qApp->closeAllWindows();
        qApp->exit(0);
    }
    else if (str == "Reverb")
        form = new fx_reverse();
    else if (str == "Compressor")
        form = new fx_compressor();
    else if (str == "Echo")
        form = new fx_echo();
    else if (str == "Chorus")
        form = new fx_chorus();
    else if (str == "Distortion")
        form = new fx_distortion();
    else if (str == "Flanger")
        form = new fx_flanger();
    else if (str == "Gargle")
        form = new fx_gargle();
    else if (str == "Parameq")
        form = new fx_parameq();
    else return;
    connect(form, SIGNAL(apply(DWORD,const void*)), this, SLOT(fx(DWORD,const void*)));
    form->show();

}

//открыть форму эффектов по клику на кнопке
void MainWindow::openForm()
{
    QPushButton* check = (QPushButton*)sender();//определяем отправителя
    QAction* act = new QAction(check->text(), this);
    form_fx(act);
}

//примениь эффект ко всем активным дорожкам
void MainWindow::fx(DWORD type, const void *params)
{
    int count = check_box.size();
    for (int i = 0; i < count; i++)
    {
        if (count != check_box.size())
            return;
        if (check_box[i]->isChecked()){
            list[i]->addFX(type, params);
            waves[i]->addFX(type, params);

        }
    }
}

void MainWindow::checkOnOff(bool value)
{
    int count = check_box.size();
    for (int i = 0; i < count; i++)
    {
        if (count != check_box.size())
            return;
        list[i]->check(value);
        check_box[i]->setChecked(value);
    }

}

void MainWindow::getDevices(QStringList dev)
{
    ui->deviceBox->addItems(dev);
}

void MainWindow::deviceChanged(int i)
{
    magic->InitDevice(i);
}

void MainWindow::magicRecord()
{
    QString fileName;
    if(isRecord){
        magic->stop();
        fileName = "record_play.png";
    }
    else{
        magic->record();
        fileName = "record_stop.png";
    }
    QPixmap record(QCoreApplication::applicationDirPath() + "/icon/" + fileName);
    QIcon ButtonIconRecord(record);
    ui->pushButton_rec->setIcon(ButtonIconRecord);
    ui->pushButton_rec->setIconSize(QSize(32,32));
    isRecord = !isRecord;
}

//добавить атрибуты выделенным дорожкам
void MainWindow::addAttribute(int value)
{
    QSlider* slid = (QSlider*)sender();
    if (slid == NULL)
        return;
    for (int i = 0; i < check_box.size(); i++)
        if (check_box[i]->isChecked())
        {
            if (slid == ui->horizontalSlider_temp)
                list[i]->addAttribute(BASS_ATTRIB_TEMPO, value);
            else if (slid == ui->horizontalSlider_pitch)
                list[i]->addAttribute(BASS_ATTRIB_TEMPO_PITCH, value);
            else if (slid == ui->horizontalSlider_freq){
                list[i]->addAttribute(BASS_ATTRIB_FREQ, value);
                qDebug()<<"value = "<<QString::number(value);
            }
        }
    calcMaxTime();
}

void MainWindow::channels()
{
    QVector<HSTREAM> chans;
    for (int i = 0; i < list.size(); i++) {
        chans.push_back(list[i]->getChannel());
    }
    emit sendChannels(chans);
}

//громкость для выделенных потоков
void MainWindow::volume(int value)
{
    int count = check_box.size();
    for (int i = 0; i < count; i++)
        if (count != check_box.size())
            return;
        else if (check_box[i]->isChecked())
        {
            list[i]->volume(value);
            list_volume[i]->setValue(value);
        }
}

void MainWindow::leftRight(int value)
{
    int count = check_box.size();
    for (int i = 0; i < count; i++)
        if (count != check_box.size())
            return;
        else if (check_box[i]->isChecked())
        {
            list[i]->leftRight(value);
            list_leftRight[i]->setValue(value);
        }
}


void MainWindow::deleteTrackSlot()
{
    int count = check_box.size();
    for (int i = 0; i < count; i++)
        if (check_box[i]->isChecked())
        {
            qDebug()<<"1";
            del(list[i]);
            qDebug()<<"2";
            if (count != check_box.size())
            {
                i--;
                count = check_box.size();
            }
            qDebug()<<"3";
        }
    qDebug()<<"4";
}

void MainWindow::delEffects()
{
    int count = check_box.size();
    for (int i = 0; i < count; i++)
        if (check_box[i]->isChecked()) {
            list[i]->del_effects();
            waves[i]->delEffects();
        }
}

void MainWindow::setTime(double arg1, double arg2)
{
    QString time;
    time.append(QString("%1").arg((int)arg1 / 60, 2, 10, QLatin1Char('0')) + ":" +
                QString("%1").arg((int)arg1 % 60, 2, 10, QLatin1Char('0')) + " / " +
                QString("%1").arg((int)arg2 / 60, 2, 10, QLatin1Char('0')) + ":" +
                QString("%1").arg((int)arg2 % 60, 2, 10, QLatin1Char('0')));

    ui->timeLabel->setText(time);
}

//пересчитать максимальное время
void MainWindow::calcMaxTime()
{
    qDebug()<<"size = "<<QString::number(list.size());
    maxTime = 0;
    int count = list.size();
    for (int i = 0; i < count; i++)
        if (count != list.size())
            return;
        else if (list[i]->getLen() > maxTime) {
            maxTime = list[i]->getLen();
            //connect(list[i], SIGNAL(endOfPlayback()), exporter, SLOT(finish()));
        }
}

